using System.Collections.Generic;
using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    internal sealed class DefaultToExpression : Expression
    {
        private static readonly ITemplateCollectionModel EmptyCollection = new SimpleCollection(new List<object>(0));

        private class EmptyStringAndSequenceImpl : ITemplateScalarModel, ITemplateSequenceModel, ITemplateHashModelEx
        {
            public string GetAsString()
            {
                return string.Empty;
            }

            public ITemplateModel Get(int i)
            {
                return null;
            }

            public ITemplateModel Get(string s)
            {
                return null;
            }

            public int Size()
            {
                return 0;
            }

            public bool IsEmpty()
            {
                return true;
            }

            public ITemplateCollectionModel Keys()
            {
                return EmptyCollection;
            }

            public ITemplateCollectionModel Values()
            {
                return EmptyCollection;
            }
        }

        private static readonly ITemplateModel EmptyStringAndSequence = new EmptyStringAndSequenceImpl();

        private readonly Expression _lhs;
        private readonly Expression _rhs;

        internal DefaultToExpression(Expression lhs, Expression rhs)
        {
            _lhs = lhs;
            _rhs = rhs;
        }

        protected override ITemplateModel _getAsTemplateModel(Environment env)
        {
            ITemplateModel left = null;
            try
            {
                left = _lhs.GetAsTemplateModel(env);
            }
            catch (InvalidReferenceException)
            {
                if (!(_lhs is ParentheticalExpression))
                {
                    throw;
                }
            }
            if (left != null) return left;
            if (_rhs == null) return EmptyStringAndSequence;
            return _rhs.GetAsTemplateModel(env);
        }

        internal override bool IsLiteral()
        {
            return false;
        }

        protected override Expression DeepCloneImpl(string name, Expression subst)
        {
            if (_rhs == null)
            {
                return new DefaultToExpression(_lhs.DeepClone(name, subst), null);
            }
            return new DefaultToExpression(_lhs.DeepClone(name, subst), _rhs.DeepClone(name, subst));
        }

        public override string GetCanonicalForm()
        {
            if (_rhs == null)
            {
                return _lhs.GetCanonicalForm() + "!";
            }
            return _lhs.GetCanonicalForm() + "!" + _rhs.GetCanonicalForm();
        }
    }
}